package microcredit.gui.selector;

import java.awt.Dimension;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

import microcredit.gui.base.BaseAction;
import net.miginfocom.swing.MigLayout;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AbstractActionPanel extends JPanel {

	private static final Log LOGGER = LogFactory.getLog(AbstractActionPanel.class);
	
	private static final String ACTION_PREFIX = "$_action_";
	
	private List<BaseAction> actions = new ArrayList<BaseAction>();
	
	protected String getActionName(Action a) {
		return ACTION_PREFIX + actions.indexOf(a);
	}
	
	protected void updateState() {
		for (BaseAction a : actions) {
			try {
				a.updateState();
			} catch (Throwable e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
	}
	
	protected void emulateActionWithoutThrow(Action action)  {
		if (action != null) {
			try {
				emulateAction(action);
			} catch (Throwable e) {
				throw new RuntimeException("Sneaked", e);
			}
		}
	}
	
	public void removeAllActions() {
		for (Action a : actions) {
			getActionMap().remove(getActionName(a));
		}
		actions.clear();
	}
	
	public void addAction(BaseAction action) {
		if (action == null) {
			return;
		}
		actions.add(action);
		getActionMap().put(getActionName(action), action);
	}
	
	protected void emulateAction(Action action) throws Throwable {
		if (action != null) {
			if (action instanceof BaseAction) {
				((BaseAction) action).emulate(new ActionEvent(this, 0, "emulate"));
			} else {
				action.actionPerformed(new ActionEvent(this, 0, "emulate"));
			}
		}
	}

	protected JButton createButton() {
		return new ActionButton();
	}
	
	protected JButton createButton(BaseAction action) {
		return new ActionButton(action);
	}

	public class ToggleActionButton extends JToggleButton {

		public ToggleActionButton() {
			super();
			init();
		}

		public ToggleActionButton(Action a) {
			super(a);
			init();
		}

		public ToggleActionButton(Icon icon, boolean selected) {
			super(icon, selected);
			init();
		}

		public ToggleActionButton(Icon icon) {
			super(icon);
			init();
		}

		public ToggleActionButton(String text, boolean selected) {
			super(text, selected);
			init();
		}

		public ToggleActionButton(String text, Icon icon, boolean selected) {
			super(text, icon, selected);
			init();
		}

		public ToggleActionButton(String text, Icon icon) {
			super(text, icon);
			init();
		}

		public ToggleActionButton(String text) {
			super(text);
			init();
		}
		
		
		private void init() {
			addPropertyChangeListener("enabled", new PropertyChangeListener() {
				@Override
				public void propertyChange(PropertyChangeEvent evt) {
					if (isEnabled()) {
						setForeground(SystemColor.textText);
					} else {
						setForeground(SystemColor.textInactiveText);
					}
				}
			});
			setRequestFocusEnabled(false);
		}
		
		@Override
		protected void configurePropertiesFromAction(Action a) {
			super.configurePropertiesFromAction(a);
			applyKeyStroke(a);
		}
		
		private void applyKeyStroke(Action a) {
			String text = (String)a.getValue(Action.NAME);
			KeyStroke stroke = (KeyStroke)a.getValue(Action.ACCELERATOR_KEY);
			if (stroke != null) {
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_IN_FOCUSED_WINDOW).put(stroke, getActionName(a));
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_FOCUSED).put(stroke, getActionName(a));
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, getActionName(a));
				
				StringBuilder builder = new StringBuilder();
				builder.append("<html>").append(text);
				builder.append("<font size='-2'> (");
				if (stroke.getModifiers() > 0) {
					builder.append(KeyEvent.getKeyModifiersText(stroke.getModifiers()));
					builder.append("+");
				}
				builder.append(KeyEvent.getKeyText(stroke.getKeyCode()));
				builder.append(")</font>");
				setText(builder.toString());
			} else {
				setText(text);
			}
		}
		
		@Override
		protected void actionPropertyChanged(Action action, String propertyName) {
			super.actionPropertyChanged(action, propertyName);
			if (propertyName.equals(Action.NAME) || propertyName.equals(Action.ACCELERATOR_KEY)) {
				applyKeyStroke(action);
			}
		}
	}
	
	public class ActionButton extends JButton {
		
		public ActionButton() {
			super();
			init();
		}

		public ActionButton(Action a) {
			super(a);
			init();
		}

		public ActionButton(Icon icon) {
			super(icon);
			init();
		}

		public ActionButton(String text, Icon icon) {
			super(text, icon);
			init();
		}

		public ActionButton(String text) {
			super(text);
			init();
		}

		public ActionButton(BaseAction action) {
			super(action);
			init();
		}
		
		private void init() {
			addPropertyChangeListener("enabled", new PropertyChangeListener() {
				@Override
				public void propertyChange(PropertyChangeEvent evt) {
					if (isEnabled()) {
						setForeground(SystemColor.textText);
					} else {
						setForeground(SystemColor.textInactiveText);
					}
				}
			});
			setRequestFocusEnabled(false);
		}
		
		@Override
		protected void configurePropertiesFromAction(Action a) {
			super.configurePropertiesFromAction(a);
			applyKeyStroke(a);
		}
		
		private void applyKeyStroke(Action a) {
			String text = (String)a.getValue(Action.NAME);
			KeyStroke stroke = (KeyStroke)a.getValue(Action.ACCELERATOR_KEY);
			if (stroke != null) {
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_IN_FOCUSED_WINDOW).put(stroke, getActionName(a));
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_FOCUSED).put(stroke, getActionName(a));
				AbstractActionPanel.this.getInputMap(AbstractButtonPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, getActionName(a));
				
				StringBuilder builder = new StringBuilder();
				builder.append("<html>").append(text);
				builder.append("<font size='-2'> (");
				if (stroke.getModifiers() > 0) {
					builder.append(KeyEvent.getKeyModifiersText(stroke.getModifiers()));
					builder.append("+");
				}
				builder.append(KeyEvent.getKeyText(stroke.getKeyCode()));
				builder.append(")</font>");
				setText(builder.toString());
			} else {
				setText(text);
			}
		}
		
		@Override
		protected void actionPropertyChanged(Action action, String propertyName) {
			super.actionPropertyChanged(action, propertyName);
			if (propertyName.equals(Action.NAME) || propertyName.equals(Action.ACCELERATOR_KEY)) {
				applyKeyStroke(action);
			}
		}
	}
	
	public class MToolBar extends JToolBar {
		
		public MToolBar() {
			setFloatable(false);
			setBorderPainted(false);
			setOpaque(false);
			setInsetsEnabled(true);
		}
		
		public void setInsetsEnabled(boolean enabled) {
			if (enabled) {
				setLayout(new MigLayout("insets 2 5 2 5", "[fill]3", "[fill, 28!]"));
			} else {
				setLayout(new MigLayout("insets 0", "[fill]3", "[fill, 28!]"));
			}
		}
		
		public ActionButton addAction(BaseAction action) {
			ActionButton b = new ActionButton(action);
			b.setPreferredSize(new Dimension(b.getPreferredSize().width-14, b.getPreferredSize().height));
			add(b);
			return b;
		}
		
		public ToggleActionButton addToggleAction(BaseAction action) {
			ToggleActionButton b = new ToggleActionButton(action);
			b.setPreferredSize(new Dimension(b.getPreferredSize().width-14, b.getPreferredSize().height));
			add(b);
			return b;
		}
		
		
		public void addExpander() {
			add(new JLabel(""), "pushx 1");
		}
	}
	
}
